use anyhow::Result;
use clap::{Arg, Command};
use cluster_node_manager::{ClusterManager, Config as AppConfig};
use std::path::PathBuf;
use tracing::{error, info};

#[tokio::main]
async fn main() -> Result<()> {
    // 程序入口: 初始化日志 / 解析命令行参数 / 准备运行目录
    // TODO: 后续补充: 读取配置 -> 构建 ClusterManager -> 启动 -> 阻塞等待信号优雅退出
    // Initialize tracing
    tracing_subscriber::fmt().with_env_filter("info").init();

    let app = Command::new("cluster-node-manager")
        .version("0.1.0")
        .about("A large-scale cluster node management tool based on Raft and Tokio")
        .arg(
            Arg::new("config")
                .short('c')
                .long("config")
                .value_name("FILE")
                .help("Configuration file path")
                .default_value("config/config.yaml"),
        )
        .arg(
            Arg::new("node-id")
                .short('n')
                .long("node-id")
                .value_name("ID")
                .help("Node ID for this instance")
                .default_value("1"),
        )
        .arg(
            Arg::new("api-port")
                .short('p')
                .long("api-port")
                .value_name("PORT")
                .help("API server port")
                .default_value("8080"),
        )
        .arg(
            Arg::new("raft-port")
                .short('r')
                .long("raft-port")
                .value_name("PORT")
                .help("Raft communication port")
                .default_value("9090"),
        )
        .arg(
            Arg::new("data-dir")
                .short('d')
                .long("data-dir")
                .value_name("DIR")
                .help("Data directory")
                .default_value("./data"),
        );

    let matches = app.get_matches();

    let config_path = matches.get_one::<String>("config").unwrap();
    let node_id = matches.get_one::<String>("node-id").unwrap();
    let api_port = matches.get_one::<String>("api-port").unwrap();
    let raft_port = matches.get_one::<String>("raft-port").unwrap();
    let data_dir = matches.get_one::<String>("data-dir").unwrap();

    info!("Starting cluster node manager");
    info!("Node ID: {}", node_id);
    info!("Config file: {}", config_path);
    info!("API port: {}", api_port);
    info!("Raft port: {}", raft_port);
    info!("Data directory: {}", data_dir);

    // Create data directory if it doesn't exist
    let data_path = PathBuf::from(data_dir);
    if !data_path.exists() {
        std::fs::create_dir_all(&data_path)?;
        info!("Created data directory: {}", data_dir);
    }

    // Load configuration file
    let mut config = if std::path::Path::new(config_path).exists() {
        match AppConfig::from_file(config_path) {
            Ok(c) => c,
            Err(e) => {
                error!("Failed to load config file: {}. Using defaults", e);
                AppConfig::default()
            }
        }
    } else {
        info!("Config file not found, using defaults");
        AppConfig::default()
    };

    // Override node id & bind ports from CLI
    if let Ok(id) = node_id.parse::<u64>() {
        config.node.id = id;
    }
    config.node.bind_addr = format!("0.0.0.0:{}", raft_port);
    config.api.bind_addr = format!("0.0.0.0:{}", api_port);
    config.node.data_dir = data_path.clone();

    // Merge environment
    if let Err(e) = config.merge_env() {
        error!("Failed to merge env vars: {}", e);
    }
    if let Err(e) = config.validate() {
        error!("Config validation failed: {}", e);
    }

    // Build cluster manager
    let cluster_manager = ClusterManager::new(config.clone()).await?;

    // Decide whether to bootstrap or join
    if config.cluster.peers.is_empty()
        || (config.cluster.peers.len() == 1
            && config.cluster.peers[0]
                .split(':')
                .next()
                .map(|s| s == node_id)
                .unwrap_or(false))
    {
        info!("Bootstrapping new cluster");
        if let Err(e) = cluster_manager.initialize_cluster().await {
            error!("Cluster initialization failed: {}", e);
        }
    } else {
        info!("Joining existing cluster: peers={:?}", config.cluster.peers);
        if let Err(e) = cluster_manager.join_cluster().await {
            error!("Failed to join cluster: {}", e);
        }
    }

    // Start runtime components
    cluster_manager.start().await?;
    info!("Cluster Node Manager started. Waiting for shutdown signal (Ctrl+C)...");

    // Wait for termination signals
    #[cfg(unix)]
    {
        tokio::select! {
            _ = tokio::signal::ctrl_c() => { info!("Received Ctrl+C"); }
            _ = async {
                use tokio::signal::unix::{signal, SignalKind};
                let mut sigterm = signal(SignalKind::terminate()).expect("install SIGTERM handler");
                sigterm.recv().await;
            } => { info!("Received SIGTERM"); }
        }
    }
    #[cfg(not(unix))]
    {
        tokio::signal::ctrl_c().await?;
    }

    info!("Shutting down cluster...");
    if let Err(e) = cluster_manager.shutdown().await {
        error!("Shutdown error: {}", e);
    }
    info!("Shutdown complete");

    Ok(())
}
